/**
 * Copyright 2000 self.com.au
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License. (http://www.apache.org/licenses/LICENSE-2.0)
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed 
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for 
 * the specific language governing permissions and limitations under the License.
 *
 * <dhamma-message src="Atisha (11th century Tibetan Buddhist master)">
 * 	The greatest achievement is selflessness. The greatest worth is self-mastery.
 * 	The greatest quality is seeking to serve others. The greatest precept is continual awareness.
 * 	The greatest medicine is the emptiness of everything. The greatest action is not conforming with the worlds ways.
 * 	The greatest magic is transmuting the passions. The greatest generosity is non-attachment.
 * 	The greatest goodness is a peaceful mind. The greatest patience is humility.
 * 	The greatest effort is not concerned with results. The greatest meditation is a mind that lets go.
 * 	The greatest wisdom is seeing through appearances. 
 * </dhamma-message>
 *
 * @author Ashin Wimalajeewa
 */
package self.amigo.editor.tool;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

import self.util.*;
import self.math.geom.*;
import self.swing.*;
import self.gee.*;
import self.amigo.editor.*;
import self.amigo.elem.*;


public class SelfReferencingLinkTool extends ACreationTool {
  final static private int SIZE_FROM_PERIM = 15;

  private LinkView        main;
  private BasicLinkView   view;
  private boolean linkCompleted = true;
  private ILinkableGraphic sideA, sideB; 
  private Point a, b, c, d, e;
  private Point tl, tr, bl, br, centre;
  private int[] closestDist = new int[4];
  private int currQuadrant = -1;
  
  
  public SelfReferencingLinkTool() {
    userInterfaceSink.putValue( Action.NAME, "Self Ref.Link" );
    Icon gif = IconUtils.getIconWithDescription("/self/amigo/images/SelfRef.gif", getToolTip() );
    userInterfaceSink.putValue( Action.SMALL_ICON, gif );
  }
  
  protected String getToolTip() {
    return "Self referencing Link";
  }

  protected IGraphicElement getCreatedElement() {
    return main;
  }
  
  protected void cancelElementCreation() {
    if ( main != null )
      main.remove();
    linkCompleted = true;
  }
  
  protected LinkView constructLinkView() {
    return new LinkView();
  }
  
  public void mouseReleased(MouseEvent event) {
    if (!linkCompleted) 
      editor.getSource().redraw();
    linkCompleted = true;
    super.mouseReleased(event);
  }
  
  public void mouseMoved(MouseEvent event) {
    if (!linkCompleted) 
      sizeCreatedViewElement(event);
  }
  
  protected void createViewElement( MouseEvent me ) {
    if ( linkCompleted ) {
      IGraphicElement elem = controller.diagramLayer.getElementAtPoint( controller.touchDown );
      if ( !(elem instanceof ILinkableGraphic) ) 
        return;
      linkCompleted = false;
      main = constructLinkView();
      main.setLayer( controller.diagramLayer, true );

      a = new Point();
      b = new Point();
      c = new Point();
      d = new Point();
      e = new Point();

      view = main.getBasicLink();
      view.addPoint( a );
      view.addPoint( b );
      view.addPoint( c );
      view.addPoint( d );
      view.addPoint( e );
      sideA = (ILinkableGraphic) elem;
      sideB = (ILinkableGraphic) elem;
      initHostBounds();
      establishLinksToElements();
      sizeCreatedViewElement( me );
    } 
  }
  
  private void initHostBounds() {
    Rectangle bnds = sideA.getBounds();
    tl = new Point( bnds.x, bnds.y );
    bl = new Point( bnds.x, bnds.y + bnds.height );
    tr = new Point( bnds.x + bnds.width, bnds.y );
    br = new Point( bnds.x + bnds.width, bnds.y + bnds.height );
    centre = new Point( bnds.x + (bnds.width/2), bnds.y + (bnds.height/2) );
  }
  
  private int getClosestToPoint( int x, int y ) {
   closestDist[0] = (int) PointUtils.getDistance( tl.x, tl.y, x, y );
   closestDist[1] = (int) PointUtils.getDistance( tr.x, tr.y, x, y );
   closestDist[2] = (int) PointUtils.getDistance( br.x, br.y, x, y );
   closestDist[3] = (int) PointUtils.getDistance( bl.x, bl.y, x, y );
   return Arrays.min( closestDist );
  }
  
  protected void sizeCreatedViewElement(MouseEvent event) {
    if ( !linkCompleted ) {
      int quad = getClosestToPoint(event.getX(), event.getY());
      if ( currQuadrant == quad )
        return;
      currQuadrant = quad;
      controller.diagramLayer.beginUpdate();
      switch ( currQuadrant ) {
        case 0: setPointsForTopLeft(); break;
        case 1: setPointsForTopRight(); break;
        case 2: setPointsForBottomRight(); break;
        case 3: setPointsForBottomLeft(); break;
      }
      controller.diagramLayer.endUpdate();
    } 
  }
  
  private void setPointsForTopLeft() {
    a.setLocation( tl.x, centre.y );
    b.setLocation( tl.x - SIZE_FROM_PERIM, centre.y );
    c.setLocation( tl.x - SIZE_FROM_PERIM, tl.y - SIZE_FROM_PERIM );
    d.setLocation( centre.x, tl.y - SIZE_FROM_PERIM );
    e.setLocation( centre.x, tl.y );
  }
  
  private void setPointsForTopRight() {
    a.setLocation( centre.x, tr.y );
    b.setLocation( centre.x, tr.y - SIZE_FROM_PERIM );
    c.setLocation( tr.x + SIZE_FROM_PERIM, tr.y - SIZE_FROM_PERIM );
    d.setLocation( tr.x + SIZE_FROM_PERIM, centre.y );
    e.setLocation( tr.x, centre.y );
  }
  
  private void setPointsForBottomRight() {
    a.setLocation( br.x, centre.y );
    b.setLocation( br.x + SIZE_FROM_PERIM, centre.y );
    c.setLocation( br.x + SIZE_FROM_PERIM, br.y + SIZE_FROM_PERIM );
    d.setLocation( centre.x, br.y + SIZE_FROM_PERIM );
    e.setLocation( centre.x, br.y );
  }
  
  private void setPointsForBottomLeft() {
    a.setLocation( centre.x, bl.y );
    b.setLocation( centre.x, bl.y + SIZE_FROM_PERIM );
    c.setLocation( bl.x - SIZE_FROM_PERIM, bl.y + SIZE_FROM_PERIM );
    d.setLocation( bl.x - SIZE_FROM_PERIM, centre.y );
    e.setLocation( bl.x, centre.y );
  }
  
  private void establishLinksToElements() {
    view.linkSideA( sideA );
    view.linkSideB( sideB );
 }
}
